### 第15课 语音控制智慧校园

#### 15.1 项目介绍

经过前面一系列的语音控制项目的学习，我们是不是可以通过智能语音模块控制智慧校园更多传感器模块呢？当然是可以的。在本项目实验中，通过ESP32主控板控制更多传感器模块，然后通过智能语音模块进行实时语音播报智慧校园教室内的温度、湿度、空气质量和光照强度等。同时，它还能控制路灯进行照明、教室内的SK6812 RGB灯亮不同颜色灯，校门开与关、窗帘拉开与关闭、校园入侵警报、旗帜升降和音乐播放等。


#### 15.2 流程图

![project20](../../img/project20.png)

#### 15.3 实验代码

```c++
// 导入库文件
#include <SoftwareSerial.h>
#include <DFRobot_ENS160.h>
#include <BuzzerESP32.h> 
#include <Wire.h>
#include <AHT20.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
 #include <avr/power.h> // 需要 16 MHz Adafruit Trinket
#endif
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#include <Stepper.h>   // 提供了控制步进电机的基本功能
#include <ESP32Servo.h> 
Servo myservo;  // 创建舵机对象来控制舵机,在ESP32上可以创建16个舵机对象

// 定义光敏电阻传感器引脚
const int PhotoresistorPin = 34;
// 定义LED引脚 
const int LED_PIN = 12;  
// 定义无源蜂鸣器引脚
BuzzerESP32 buzzer(19); 
// 步进电机驱动板参数（28BYJ-48）
const int STEPS_PER_REV = 2038;  // 实际步数/圈（不同电机可能有差异）
const int MOTOR_PIN1 = 14;       // IN1
const int MOTOR_PIN2 = 27;       // IN2
const int MOTOR_PIN3 = 16;       // IN3
const int MOTOR_PIN4 = 17;       // IN4

// 用户可调参数(步进电机)
int motorSpeed = 10;      // 转速(RPM)，建议5-12，超过15极易堵转
int rotationCount = 2;    // 转动圈数
bool reverseDirection = false; // 反转标志位

// 初始化步进电机（注意引脚顺序IN1-IN3-IN2-IN4）
Stepper myStepper(STEPS_PER_REV, MOTOR_PIN1, MOTOR_PIN3, MOTOR_PIN2, MOTOR_PIN4);

// 电机控制状态
bool motorRunning = false;
unsigned long motorStartTime = 0;
const unsigned long MOTOR_DURATION = 800;  // 0.8秒
int currentDirection = 0;  // 0:停止, 1:正转, 2:反转

#define RGB_PIN 4      // 控制信号引脚
#define LED_COUNT 4    // LED 灯珠数量

// 创建 NeoPixel 对象
Adafruit_NeoPixel strip(LED_COUNT, RGB_PIN, NEO_GRB + NEO_KHZ800);

// 电机驱动引脚定义
const int INA = 5;  
const int INB = 13; 

const int ServoPin = 32; // 舵机的引脚

const int RX_PIN = 25; // 引脚 GPIO25 为 RX
const int TX_PIN = 26; // 引脚 GPIO26 为 TX

SoftwareSerial mySerial(RX_PIN, TX_PIN); // 定义软件串口引脚（RX, TX）

// 定义变量用于存储从语音模块接收到的控制码
volatile int Voice_Control = 0;  // 初始化为0，确保首次判断时不触发任何指令

// OLED配置
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1  // 共用I2C复位
#define I2C_ADDRESS 0x3C  // SH1106默认地址

// 创建对象
AHT20 aht20;
DFRobot_ENS160_I2C ENS160(&Wire, 0x53);
Adafruit_SH1106G display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// 定义变量
int Temperature = 0;
int Humidity = 0;
int Intensity = 0;

// 上次更新时间
unsigned long lastUpdate = 0; // 记录上次更新时间
const unsigned long updateInterval = 500; // 0.5秒更新间隔

// 串口发送消息最大长度
#define UART_SEND_MAX      32
#define UART_MSG_HEAD_LEN  2
#define UART_MSG_FOOT_LEN  2

// 串口发送消息号
#define U_MSG_bozhensgshu      1
#define U_MSG_boxiaoshu      2
#define U_MSG_bobao1      3
#define U_MSG_bobao2      4
#define U_MSG_bobao3      5
#define U_MSG_bobao4      6
#define U_MSG_bobao5      7
#define U_MSG_bobao6      8
#define U_MSG_bobao7      9
#define U_MSG_bobao8      10
#define U_MSG_bobao9      11
#define U_MSG_bobao10      12
#define U_MSG_bobao11      13
#define U_MSG_bobao12      14
#define U_MSG_bobao13      15
#define U_MSG_bobao14      16
#define U_MSG_bobao15      17
#define U_MSG_bobao16      18
#define U_MSG_bobao17      19
#define U_MSG_bobao18      20
#define U_MSG_bobao19      21
#define U_MSG_bobao20      22
#define U_MSG_bobao21      23

// 串口消息参数类型
typedef union {
  double d_double;
  int d_int;
  unsigned char d_ucs[8];
  char d_char;
  unsigned char d_uchar;
  unsigned long d_long;
  short d_short;
  float d_float;}uart_param_t;

// 串口发送函数实现
void _uart_send_impl(unsigned char* buff, int len) {
  // TODO: 调用项目实际的串口发送函数
  for(int i=0;i<len;i++){
    mySerial.write (*buff++);
  }
}

// 串口通信消息尾
const unsigned char g_uart_send_foot[] = {
  0x55, 0xaa
};

// 十六位整数转32位整数
void _int16_to_int32(uart_param_t* param) {
  if (sizeof(int) >= 4)
    return;
  unsigned long value = param->d_long;
  unsigned long sign = (value >> 15) & 1;
  unsigned long v = value;
  if (sign)
    v = 0xFFFF0000 | value;
  uart_param_t p;  p.d_long = v;
  param->d_ucs[0] = p.d_ucs[0];
  param->d_ucs[1] = p.d_ucs[1];
  param->d_ucs[2] = p.d_ucs[2];
  param->d_ucs[3] = p.d_ucs[3];
}

// 浮点数转双精度
void _float_to_double(uart_param_t* param) {
  if (sizeof(int) >= 4)
    return;
  unsigned long value = param->d_long;
  unsigned long sign = value >> 31;
  unsigned long M = value & 0x007FFFFF;
  unsigned long e =  ((value >> 23 ) & 0xFF) - 127 + 1023;
  uart_param_t p0, p1;
  p1.d_long = ((sign & 1) << 31) | ((e & 0x7FF) << 20) | (M >> 3);
  param->d_ucs[0] = p0.d_ucs[0];
  param->d_ucs[1] = p0.d_ucs[1];
  param->d_ucs[2] = p0.d_ucs[2];
  param->d_ucs[3] = p0.d_ucs[3];
  param->d_ucs[4] = p1.d_ucs[0];
  param->d_ucs[5] = p1.d_ucs[1];
  param->d_ucs[6] = p1.d_ucs[2];
  param->d_ucs[7] = p1.d_ucs[3];
}

// 串口通信消息头
const unsigned char g_uart_send_head[] = {
  0xaa, 0x55
};

// 播报函数1
void _uart_bobao1() {
  uart_param_t param;
    int i = 0;
    unsigned char buff[UART_SEND_MAX] = {0};
    for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
        buff[i + 0] = g_uart_send_head[i];
    }
    buff[2] = U_MSG_bobao1;
    for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
        buff[i + 3] = g_uart_send_foot[i];
    }
    _uart_send_impl(buff, 5);
}

// 播报函数2
void _uart_bobao2() {
  uart_param_t param;
    int i = 0;
    unsigned char buff[UART_SEND_MAX] = {0};
    for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
        buff[i + 0] = g_uart_send_head[i];
    }
    buff[2] = U_MSG_bobao2;
    for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
        buff[i + 3] = g_uart_send_foot[i];
    }
    _uart_send_impl(buff, 5);
}
// 播报函数4
void _uart_bobao4() {
  uart_param_t param;
  int i = 0;
  unsigned char buff[UART_SEND_MAX] = {0};
  for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
       buff[i + 0] = g_uart_send_head[i];
    }
  buff[2] = U_MSG_bobao4;
  for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
       buff[i + 3] = g_uart_send_foot[i];
   }
  _uart_send_impl(buff, 5);
}

// 播报函数5
void _uart_bobao5() {
  uart_param_t param;
  int i = 0;
  unsigned char buff[UART_SEND_MAX] = {0};
  for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
       buff[i + 0] = g_uart_send_head[i];
    }
  buff[2] = U_MSG_bobao5;
  for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
       buff[i + 3] = g_uart_send_foot[i];
   }
  _uart_send_impl(buff, 5);
}

// 播报函数19
void _uart_bobao19() {
  uart_param_t param;
  int i = 0;
  unsigned char buff[UART_SEND_MAX] = {0};
  for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
       buff[i + 0] = g_uart_send_head[i];
    }
  buff[2] = U_MSG_bobao19;
  for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
       buff[i + 3] = g_uart_send_foot[i];
   }
  _uart_send_impl(buff, 5);
}

// 播报函数20
void _uart_bobao20() {
  uart_param_t param;
  int i = 0;
  unsigned char buff[UART_SEND_MAX] = {0};
  for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
       buff[i + 0] = g_uart_send_head[i];
    }
  buff[2] = U_MSG_bobao20;
  for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
       buff[i + 3] = g_uart_send_foot[i];
   }
  _uart_send_impl(buff, 5);
}

// 播报函数21
void _uart_bobao21() {
  uart_param_t param;
  int i = 0;
  unsigned char buff[UART_SEND_MAX] = {0};
  for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
       buff[i + 0] = g_uart_send_head[i];
    }
  buff[2] = U_MSG_bobao21;
  for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
       buff[i + 3] = g_uart_send_foot[i];
   }
  _uart_send_impl(buff, 5);
}

// 播报整数
void _uart_bozhensgshu(int zhengshu) {
  uart_param_t param;
    int i = 0;
    unsigned char buff[UART_SEND_MAX] = {0};
    for (i = 0; i < UART_MSG_HEAD_LEN; i++) {
        buff[i + 0] = g_uart_send_head[i];
    }
    buff[2] = U_MSG_bozhensgshu;
    param.d_int = zhengshu;
    _int16_to_int32(&param);
    buff[3] = param.d_ucs[0];
    buff[4] = param.d_ucs[1];
    buff[5] = 0;
    buff[6] = 0;
    for (i = 0; i < UART_MSG_FOOT_LEN; i++) {
        buff[i + 7] = g_uart_send_foot[i];
    }
    _uart_send_impl(buff, 9);
}

void setup(){
   Serial.begin(9600); // 硬件串口（与电脑通信）
   mySerial.begin(9600); // 软件串口（与外设通信）
   Wire.begin(); // 初始化I2C总线
   
   // 初始化LED引脚
   pinMode(LED_PIN, OUTPUT);
   digitalWrite(LED_PIN, LOW);

   // 初始化步进电机的速度
   myStepper.setSpeed(10);
   pinMode(INA, OUTPUT);
   pinMode(INB, OUTPUT);
   
   // 调整旗帜的等待时间
   stopMotor();
   delay(3000);
   
   myservo.attach(ServoPin);   // 将引脚io23上的舵机连接到舵机对象上
   myservo.write(90); // 舵机角度为90°
   delay(1000); // 延时1s
   
   #if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
     clock_prescale_set(clock_div_1);
   #endif
   strip.begin();           // 初始化新像素条
   strip.show();            // 关闭所有像素
   strip.setBrightness(100); // 设置亮度（最大255）
   
   // 初始化OLED
   display.begin(I2C_ADDRESS, true);
   display.clearDisplay();
   display.setTextSize(1);
   display.setTextColor(SH110X_WHITE);
  
   // 初始化传感器
   aht20.begin();
   ENS160.begin();
   ENS160.setPWRMode(ENS160_STANDARD_MODE);
}

void loop(){
  // 非阻塞电机运行控制
  if (motorRunning && (millis() - motorStartTime >= MOTOR_DURATION)) {
    stopMotor();
    motorRunning = false;
    currentDirection = 0;
  }
  if (millis() - lastUpdate >= updateInterval) {
    lastUpdate = millis();

    Temperature = aht20.getTemperature(); // 直接从AHT20传感器读取温度数据
    Humidity = aht20.getHumidity(); // 直接从AHT20传感器读取湿度数据
    Intensity = analogRead(PhotoresistorPin); // 获取光敏电阻传感器检测的光照强度
    uint8_t Status = ENS160.getENS160Status(); // 获取ENS160传感器工作状态
    uint8_t AQI = ENS160.getAQI(); // 获取ENS160传感器检测的空气质量指数(1-5)
    uint16_t TVOC = ENS160.getTVOC(); // 获取ENS160传感器检测的TVOC浓度(0-65000 ppb)
    uint16_t ECO2 = ENS160.getECO2(); // 获取ENS160传感器检测的等效CO2浓度(400-65000 ppm)
    // 精简的OLED显示更新
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(20, 0);
    display.println("Voice-controlled");
    display.setCursor(30, 20);
    display.println("Smart School");
    display.display();
    if (mySerial.available() > 0) {  // 持续检查软串口是否有来自语音模块的数据
      Voice_Control = mySerial.read();  // 读取一个字节的数据
      Serial.println(Voice_Control);   // 将接收到的数据通过硬件串口输出，便于调试和监控
    } 
    if (Voice_Control == 47) { // 判断接收到的指令数值47,并执行相应操作
      delay(2 * 1000);
      _uart_bobao1();
      delay(2 * 1000);
      _uart_bozhensgshu(Temperature); // 语音播报当前检测到的温度值
      delay(2 * 1000);
      _uart_bobao2();
      delay(1 * 1000);
    } else if (Voice_Control == 48) { // 判断接收到的指令数值48,并执行相应操作
      delay(2 * 1000);
      _uart_bobao4();
      delay(2 * 1000);
      _uart_bozhensgshu(Humidity); // 语音播报当前检测到的湿度值
      delay(1 * 1000);
    } else if (Voice_Control == 50) { // 判断接收到的指令数值50,并执行相应操作
      delay(2 * 1000);
      _uart_bobao5();
      delay(2 * 1000);
      _uart_bozhensgshu(Intensity); // 语音播报当前检测到的光照强度值
      delay(1 * 1000);
    } else if (Voice_Control == 65) { // 判断接收到的指令数值65,并执行相应操作
      delay(4 * 1000);
      _uart_bobao19();
      delay(4 * 1000);
      _uart_bozhensgshu(TVOC); // 语音播报当前检测到的总挥发性有机物浓度
      delay(1 * 1000);
    } else if (Voice_Control == 66) {  // 判断接收到的指令数值66,并执行相应操作
      delay(3 * 1000);
      _uart_bobao20();
      delay(3 * 1000);
      _uart_bozhensgshu(ECO2); // 语音播报当前二氧化碳浓度
      delay(1 * 1000);
    } else if (Voice_Control == 67) { // 判断接收到的指令数值67,并执行相应操作
      delay(3 * 1000);
      _uart_bobao21();
      delay(2 * 1000);
      _uart_bozhensgshu(AQI); // 语音播报当前空气质量指数
      delay(1 * 1000);
    } else if (Voice_Control == 1) { // 接收到的数据(命令参数)为1, 并执行相应操作
      digitalWrite(LED_PIN, HIGH); // 打开LED,灯点亮
    } else if (Voice_Control == 2) { // 接收到的数据为2,并执行相应操作
      digitalWrite(LED_PIN, LOW); // 关闭LED
    } else if (Voice_Control == 21) { // 接收到的数据为21,并执行相应操作
      buzzer.playTone(532, 250);  // 蜂鸣器鸣叫
      delay(100);
      buzzer.playTone(0, 0);  // 蜂鸣器不响
      delay(100);
    } else if (Voice_Control == 22) { // 接收到的数据为22,并执行相应操作
      buzzer.playTone(0, 0);   
    } else if (Voice_Control == 59) { // 接收到的数据为59,并执行相应操作
      myservo.write(180); // 舵机转动,开门
      delay(1000);
    } else if (Voice_Control == 60) { // 接收到的数据为60,并执行相应操作
      myservo.write(90); // 舵机转动,关门
      delay(1000);
    } else if (Voice_Control == 62) { // 接收到的数据为62,并执行相应操作
      startMotor(2); // 降旗
    } else if (Voice_Control == 61) { // 接收到的数据为61,并执行相应操作
      startMotor(1); // 升旗
    } else if (Voice_Control == 63) { // 接收到的数据为63,并执行相应操作
      myStepper.step(STEPS_PER_REV * 2); // 拉开窗帘
    } else if (Voice_Control == 64) { // 接收到的数据为64,并执行相应操作
      myStepper.step(STEPS_PER_REV * -2); // 关闭窗帘
    } else if (Voice_Control == 11) { // 接收到的数据为11,并执行相应操作
      birthday(); // 蜂鸣器播放音乐
    } else if (Voice_Control == 12) { // 接收到的数据为12,并执行相应操作
      buzzer.playTone(0, 0); // 蜂鸣器不响
    } else if (Voice_Control == 13) { // 接收到的数据为13,并执行相应操作
      colorWipe(strip.Color(255, 0, 0), 50); // SK6812 RGB灯亮红灯
    } else if (Voice_Control == 14) { // 接收到的数据为14,并执行相应操作
      colorWipe(strip.Color(0, 0, 0), 50); // SK6812 RGB灯熄灭
    } else if (Voice_Control == 15) { // 接收到的数据为15,并执行相应操作
      colorWipe(strip.Color(0, 255, 0), 50);  // SK6812 RGB灯亮绿灯
    } else if (Voice_Control == 16) { // 接收到的数据为16,并执行相应操作
      colorWipe(strip.Color(0, 0, 0), 50);
    } else if (Voice_Control == 17) { // 接收到的数据为17,并执行相应操作
      colorWipe(strip.Color(0, 0, 255), 50); // SK6812 RGB灯亮蓝灯
    } else if (Voice_Control == 18) { // 接收到的数据为18,并执行相应操作
      colorWipe(strip.Color(0, 0, 0), 50);
    }
   // 清除指令，避免重复执行
   Voice_Control = 0; 
  }
}

// 用一种颜色填充灯带
void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { 
    strip.setPixelColor(i, color); // 设置像素颜色
    strip.show();                  // 更新灯带
    delay(wait);                   // 暂停
  }
}

void startMotor(int direction) {
  stopMotor();     // 停止当前动作
  if (direction == 1) {
    analogWrite(INA, 150);
    analogWrite(INB, 0);
  } else if (direction == 2) {
    analogWrite(INA, 0);
    analogWrite(INB, 150);
  }
  motorRunning = true;
  motorStartTime = millis();
  currentDirection = direction;
}

void stopMotor() {
  analogWrite(INA, 0);
  analogWrite(INB, 0);
}

void birthday() {
  // 演奏生日旋律 - 参数为（频率，持续时间）
  buzzer.playTone(294, 250);  // D4
  buzzer.playTone(440, 250);  // A4
  buzzer.playTone(392, 250);  // G4
  buzzer.playTone(532, 250);  // C5  
  buzzer.playTone(494, 250);  // B4
  buzzer.playTone(392, 250);  // G4
  buzzer.playTone(440, 250);  // A4
  buzzer.playTone(392, 250);  // G4
  buzzer.playTone(587, 250);  // D5
  buzzer.playTone(532, 250);  // C5  
  buzzer.playTone(392, 250);  // G4
  buzzer.playTone(784, 250);  // G5
  buzzer.playTone(659, 250);  // E5
  buzzer.playTone(532, 250);  // C5  
  buzzer.playTone(494, 250);  // B4
  buzzer.playTone(440, 250);  // A4
  buzzer.playTone(698, 250);  // F5
  buzzer.playTone(659, 250);  // E5
  buzzer.playTone(532, 250);  // C5  
  buzzer.playTone(587, 250);  // D5
  buzzer.playTone(532, 500);  // C5   - 长时
  buzzer.playTone(0, 0);      // 关闭蜂鸣器
}
```
#### 15.4 实验结果

外接电源，选择好正确的开发板板型（ESP32 Dev Module）和 适当的串口端口（COMxx），然后单击![cou0](../../img/cou0.png)按钮上传代码。代码上传成功后，OLED模块显示屏显示 “Voice-controlled Smart School”。

首先，调整旗帜至下图所示位置：

![0504](../../img/0504.png)

然后，对着智能语音模块上的麦克风，使用唤醒词 “你好，小智” 或 “小智小智” 来唤醒智能语音模块，同时喇叭播放回复语 “有什么可以帮到您”；

![Voice_Controlled2](../../img/Voice_Controlled2.png)

对着麦克风说：“当前光照强度是多少” 或 “光照强度多少” 等命令词句时，接着语音播报 “正在为您读取光照强度” + “当前光照强度为” + “光敏传感器检测到的光照强度模拟值”；

智能语音模块唤醒后，对着麦克风说：“当前温度是多少” 或 “当前温度多少” 等命令词时，接着语音播报 “正在为您读取温度” + “当前温度为” + “AHT20温湿度传感器检测到的温度值” + “度”；

对着麦克风说：“当前湿度是多少” 或 “当前湿度多少” 等命令词时，接着语音播报 “正在为您读取湿度” + “当前湿度为百分之” + “AHT20温湿度传感器检测到的湿度值”；

对着麦克风说：“当前空气质量指数是多少” 等命令词时，接着语音播报 “正在为您读取空气质量指数” + “ENS160传感器模块检测到环境中的当前空气质量指数”；

对着麦克风说：“当前总挥发性有机物浓度是多少” 等命令词时，接着语音播报 “正在为您读取总挥发性有机物浓度” + “当前总挥发性有机物浓度为十亿分之” + “ENS160传感器模块检测到环境中的当前总挥发性有机物浓度值”；

对着麦克风说：“当前二氧化碳浓度是多少” 等命令词时，接着语音播报 “正在为您读取二氧化碳浓度” + “当前二氧化碳浓度为百万分之” + “ENS160传感器模块检测到环境中的当前总挥发性有机物浓度值”；

⚠️ <span style="color: rgb(255, 76, 65);">特别提醒：如果智能语音模块播报的空气质量指数(AQI)、总挥发性有机物浓度(TVOC)和二氧化碳浓度(eCO2)的数据都是0，请按一下ESP32主控板上的复位键，等待几秒钟。</span>

对着麦克风说：“请开灯” 或 “开灯” 或 “打开灯” 或 “我回来了” 等命令词时，喇叭播放对应的回复语 “已为您打开照明”，同时路灯点亮；

对着麦克风说：“请关灯” 或 “关灯” 或 “关上灯” 或 “我出去了” 等命令词时，喇叭播放对应的回复语 “已为您关闭照明”，同时路灯熄灭；

对着麦克风说：“有人” 或 “有人靠近” 或 “有人过来” 等命令词时，喇叭播放对应的回复语 “是，有人正过来”，同时无源蜂鸣器响起来；

对着麦克风说：“无人” 或 “人远离” 等命令词时，喇叭播放对应的回复语 “是，没有人”，同时无源蜂鸣器不响；

对着麦克风说：“开门” 或 “打开门”等命令词时，喇叭播放对应的回复语 “已为您打开门”，同时校门打开；

对着麦克风说：“关门” 或 “关闭门” 等命令词时，喇叭播放对应的回复语 “已为您关闭门”，同时校门关闭；

对着麦克风说：“降旗” 或 “旗子下降” 等命令词时，喇叭播放对应的回复语 “已为您降旗”，旗帜下降；

对着麦克风说：“升旗” 或 “旗子上升” 等命令词时，喇叭播放对应的回复语 “已为您升旗”，同时旗帜上升。

对着麦克风说：“拉开窗帘” 或 “开窗帘” 等命令词时，喇叭播放对应的回复语 “已为您打开窗帘”，同时窗帘缓慢拉开；

对着麦克风说：“关闭窗帘” 或 “关窗帘” 等命令词时，喇叭播放对应的回复语 “已为您关闭窗帘”，同时窗帘缓慢关闭；

对着麦克风说 “播放音乐” 等命令词时，喇叭播放对应的回复语 “已为您播放音乐”，同时蜂鸣器播放音乐；

对着麦克风说：“关闭音乐” 等命令词时，喇叭播放对应的回复语 “已为您关闭音乐”，同时蜂鸣器不响；

对着麦克风说：“打开红灯” 等命令词时，喇叭播放对应的回复语 “已为您打开红灯”，同时SK6812 RGB灯亮红色灯；

对着麦克风说：“关闭红灯” 等命令词时，喇叭播放对应的回复语 “已为您关闭红灯”，同时SK6812 RGB灯熄灭；

对着麦克风说：“打开绿灯” 等命令词时，喇叭播放对应的回复语 “已为您打开绿灯”，同时SK6812 RGB灯亮绿色灯；

对着麦克风说：“关闭绿灯” 等命令词时，喇叭播放对应的回复语 “已为您关闭绿灯”，同时SK6812 RGB灯熄灭；

对着麦克风说：“打开蓝灯” 等命令词时，喇叭播放对应的回复语 “已为您打开蓝灯”，同时SK6812 RGB灯亮蓝色灯；

对着麦克风说：“关闭蓝灯” 等命令词时，喇叭播放对应的回复语 “已为您关闭蓝灯”，同时SK6812 RGB灯熄灭。

